package widgets

import (
	"encoding/csv"
	"fmt"
	"mime"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"gitee.com/nanakura/imgui-restclient/db/model"
	g "github.com/AllenDang/giu"
	"github.com/sqweek/dialog"
	"github.com/xuri/excelize/v2"
)

func (app *MyApp) Menu() g.Widget {
	return g.MenuBar().Layout(
		g.Menu("文件").Layout(
			g.MenuItem("打开").OnClick(app.openFileDialog),
			g.MenuItem("保存").OnClick(app.saveFileDialog),
			g.Menu("另存为").Layout(
				g.MenuItem("Excel文件").OnClick(func() {
					app.saveAsFileDialog("Excel")
				}),
				g.MenuItem("CSV文件").OnClick(func() {
					app.saveAsFileDialog("CSV")
				}),
			),
		),
		g.Menu("编辑").Layout(
			g.MenuItem("清除当前请求").OnClick(app.clearCurrentRequest),
			g.MenuItem("清空历史记录").OnClick(app.clearHistory),
		),
	)
}

func (app *MyApp) clearHistory() {
	model.ClearHistory()
	app.history = []model.History{}
}

func (app *MyApp) clearCurrentRequest() {
	app.url = ""
	app.requestType = 0
	app.reqBodyEditor.Text("")
	app.contentType = 0
	app.reqResp = ""
	app.tmpParamsPairV = ""
	app.tmpParamsPairK = ""
	app.tmpHeaderPairV = ""
	app.tmpHeaderPairK = ""
	app.headersPairs = []Pair{}
	app.paramsPairs = []Pair{}
}

func (app *MyApp) openFileDialog() {
	filePath, err := dialog.File().
		Filter("Excel files", "xlsx").
		Filter("CSV files", "csv").
		Load()
	if err != nil {
		g.Msgbox("Error", err.Error())
		return
	}
	app.tmpFilePath = filePath
	fileExt := filepath.Ext(app.tmpFilePath)
	ext := mime.TypeByExtension(fileExt)
	app.clearHistory()
	app.clearCurrentRequest()
	switch ext {
	case excelExt:
		// 打开 Excel 文件
		f, err := excelize.OpenFile(app.tmpFilePath)
		if err != nil {
			g.Msgbox("Error", fmt.Sprintf("Error opening Excel file: %v", err))
			return
		}

		// 读取指定工作表的数据
		sheetName := "Sheet1"
		rows, err := f.GetRows(sheetName)
		if err != nil {
			g.Msgbox("Error", fmt.Sprintf("Error getting rows from sheet: %v", err))
			return
		}
		for i, row := range rows {
			if i == 0 {
				continue
			}
			idV, _ := strconv.Atoi(row[0])
			cTypeV, _ := strconv.Atoi(row[6])
			timeV, _ := strconv.Atoi(row[9])
			dateV, _ := time.Parse(time.DateTime, row[8])
			h := model.History{
				Id:          int32(idV),
				Method:      row[1],
				Url:         row[2],
				Headers:     row[3],
				Params:      row[4],
				Body:        row[5],
				ContentType: int32(cTypeV),
				Response:    row[7],
				Date:        dateV,
				Time:        int32(timeV),
			}
			app.history = append(app.history, h)
		}
	case csvExt:
		file, err := os.Open(app.tmpFilePath)
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
		defer file.Close()
		reader := csv.NewReader(file)
		header, err := reader.Read()
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
		idIndex := indexOf(header, "Id")
		methodIndex := indexOf(header, "Method")
		urlIndex := indexOf(header, "Url")
		headersIndex := indexOf(header, "Headers")
		paramsIndex := indexOf(header, "Params")
		bodyIndex := indexOf(header, "Body")
		responseIndex := indexOf(header, "Response")
		contentTypeIndex := indexOf(header, "ContentType")
		dateIndex := indexOf(header, "Date")
		timeIndex := indexOf(header, "Time")

		for {
			record, err := reader.Read()
			if err != nil {
				break
			}
			idV, _ := strconv.Atoi(record[idIndex])
			cTypeV, _ := strconv.Atoi(record[contentTypeIndex])
			timeV, _ := strconv.Atoi(record[timeIndex])
			dateV, _ := time.Parse(time.DateTime, record[dateIndex])
			h := model.History{
				Id:          int32(idV),
				Method:      record[methodIndex],
				Url:         record[urlIndex],
				Headers:     record[headersIndex],
				Params:      record[paramsIndex],
				Body:        record[bodyIndex],
				ContentType: int32(cTypeV),
				Response:    record[responseIndex],
				Date:        dateV,
				Time:        int32(timeV),
			}
			app.history = append(app.history, h)
		}
		// TODO sql插入数据
	}
}

func (app *MyApp) saveFileDialog() {
	if app.tmpFilePath == "" {
		filePath, err := dialog.File().
			Filter("Excel files", "xlsx").
			Filter("CSV files", "csv").
			Save()
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
		app.tmpFilePath = filePath
	}
	fileExt := filepath.Ext(app.tmpFilePath)
	ext := mime.TypeByExtension(fileExt)
	switch ext {
	case excelExt:
		app.writeHistoryToExcel(app.tmpFilePath)
	case csvExt:
		app.writeHistoryToCSV(app.tmpFilePath)
	}
}

// 辅助函数：获取字段在切片中的索引位置
func indexOf(slice []string, value string) int {
	for i, v := range slice {
		if v == value {
			return i
		}
	}
	return -1
}

var (
	csvExt   = mime.TypeByExtension(".csv")
	excelExt = mime.TypeByExtension(".xlsx")
)

func (app *MyApp) saveAsFileDialog(fileType string) {
	var filePath string
	var err error
	switch fileType {
	case "Excel":
		filePath, err = dialog.File().
			Filter("Excel files", "xlsx").
			Title("保存文件").
			Save()
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
		app.writeHistoryToExcel(filePath + ".xlsx")
	case "CSV":
		filePath, err = dialog.File().
			Filter("CSV files", "csv").
			Title("保存文件").
			Save()
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
		app.writeHistoryToCSV(filePath + ".csv")
	}
}

func (app *MyApp) writeHistoryToExcel(filePath string) {
	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
	}()
	sheetName := "Sheet1"
	index, err := f.NewSheet(sheetName)
	if err != nil {
		g.Msgbox("Error", err.Error())
		return
	}
	headers := []string{
		"Id",
		"Method",
		"Url",
		"Headers",
		"Params",
		"Body",
		"Response",
		"ContentType",
		"Date",
		"Time",
	}
	for i, header := range headers {
		idx := i + 1
		cell := toAlphaString(idx) + "1"
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
		f.SetCellValue(sheetName, cell, header)
	}
	for i, h := range app.history {
		row := i + 2
		f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), h.Id)
		f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), h.Method)
		f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), h.Url)
		f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), h.Headers)
		f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), h.Params)
		f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), h.Body)
		f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), h.Response)
		f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), h.ContentType)
		f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), h.Date)
		f.SetCellValue(sheetName, fmt.Sprintf("J%d", row), h.Time)
	}
	f.SetActiveSheet(index)
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
	if err != nil {
		g.Msgbox("Error", err.Error())
		return
	}
	defer file.Close()
	f.Write(file)
}

func toAlphaString(n int) string {
	var result string
	for n > 0 {
		n--
		result = string('A'+n%26) + result
		n /= 26
	}
	return result
}

func (app *MyApp) writeHistoryToCSV(filePath string) {
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
	if err != nil {
		g.Msgbox("Error", err.Error())
		return
	}
	defer file.Close()
	writer := csv.NewWriter(file)
	header := []string{
		"Id",
		"Method",
		"Url",
		"Headers",
		"Params",
		"Body",
		"Response",
		"ContentType",
		"Date",
		"Time",
	}
	err = writer.Write(header)
	if err != nil {
		g.Msgbox("Error", err.Error())
		return
	}
	for _, h := range app.history {
		record := []string{
			fmt.Sprintf("%d", h.Id),
			h.Method,
			h.Url,
			h.Headers,
			h.Params,
			h.Body,
			h.Response,
			fmt.Sprintf("%d", h.ContentType),
			h.Date.Format(time.DateTime),
			fmt.Sprintf("%d", h.Time),
		}
		err = writer.Write(record)
		if err != nil {
			g.Msgbox("Error", err.Error())
			return
		}
	}
	writer.Flush()
	if err := writer.Error(); err != nil {
		g.Msgbox("Error", err.Error())
		return
	}
}
